/**
 * Copyright (C) 2009-2010,  Magus Tech. Co., Ltd.
 * \file: analyze.c
 * \author: coanor
 * \date: 2010/4/15
 * \brief: transform list_t to query_t
 ******************************************************************************/
#include "parser/analyze.h"
#include "mapper/expression.hpp"
#include "parser/gram.tab.h"
#include "parser/keywords.h"
#include "mmgr/mm.h"
#include "print/print.h"

/**
 * make_parse_state_t() - line 91
 *  ParseState构造函数
 */
parse_state_t *make_parse_state_t()
{
    parse_state_t *pstate;

    pstate = (parse_state_t *)malloc(sizeof(parse_state_t));
    pstate->p_last_res_no = 1;
    pstate->p_target_res_nos = NIL;
    pstate->p_rtable = NIL;
    pstate->p_query_is_rule = 0;

    return pstate;
}

/**
 * parse_analyze()
 * \brief: analyze a list_t and transform it to query_t
 * \param: pl[in] yacc generated
 * \return:   result 转换后的Query
 * \note:
 */
query_t *parse_analyze(list_t *pl)
{
    query_t *result;
    parse_state_t *pstate;

    result = (query_t *)malloc(sizeof(query_t));

    /* 遍历List链表,对其中的每个List对象调用transformStmt,
     * 一般而言,此处的while跑一次就可以了,目前还不支持多条
     * SQL语句同时执行.
     *
     * XXX: 此处每次循环都会初始化一个pstate,转换操作执行完后
     * 该对象又被销毁,这也说明了此处List链表只处理链表头的第
     * 一个List对象.
     * 在pg的处理中,此处的result是一个指向Query的二维指针
     * ,即 query_t**,即使这里会有多个List对象被处理,其转换后
     * 的Query也以数组的形式存储在result中,最后作为返回值
     * 返回,但此处的result只是一个单一的Query*对象.
     */
    while(pl != NIL) {
        pstate = make_parse_state_t();
        result = transform_stmt(pstate, (node_t *)lfirst(pl));
        pl = lnext(pl);
        free(pstate);
    }

    return result;
}

/**
 * transform_stmt()
 * \brief: transform a list_t
 * \param: pstate[in]
 *         parseTree[in]
 * \return: result
 * \note:
 */
query_t *transform_stmt(parse_state_t *pstate, node_t *parse_tree)
{
    query_t *result = NULL;

    switch(node_tag(parse_tree))
    {
    case T_insert_stmt_t:
        result = transform_insert_stmt(pstate, (insert_stmt_t *)parse_tree);
        break;
    case T_delete_stmt_t:
        result = transform_delete_stmt(pstate, (delete_stmt_t *)parse_tree);
        break;
    case T_update_stmt_t:
        result = transform_update_stmt(pstate, (update_stmt_t *)parse_tree);
        break;
    case T_select_stmt_t:
        result = transform_select_stmt(pstate, (select_stmt_t *)parse_tree);
        break;
    default:
        /* other statments don't require any transformation-- just
         * return the original parsetree
         */
        result = make_node(query_t);
        result->command_type = CMD_UTILITY;
        result->utility_stmt = (node_t *)parse_tree;
        break;
    }
    return result;
}

/**
 * transformDeleteStmt() - line 237
 * 转化一个DELETE语句
 */
query_t* transform_delete_stmt(parse_state_t *pstate, delete_stmt_t *stmt)
{
    query_t *qry = make_node(query_t);
    qry->command_type = CMD_DELETE;

    /* 设置表范围(range table) */
    make_range_table(pstate, stmt->rel_name, NULL);

    qry->unique_flag = NULL;

    /* 转换WHERE子句 */
    qry->qual = transform_where_clause(pstate, stmt->where_clause);

    qry->rtable = pstate->p_rtable;

    qry->result_relation = range_table_posn(pstate->p_rtable, stmt->rel_name);

    return (query_t *)qry;
}

/**
 * transform_select_stmt() - line 267
 * 转化一个INSERT语句. */
query_t *transform_insert_stmt(parse_state_t *pstate, insert_stmt_t *stmt)
{
    query_t *qry = make_node(query_t);	/* 新建一个查询树 */
    list_t *targetlist;

    qry->command_type = CMD_INSERT;

    /* 设置表范围 */
    make_range_table(pstate, stmt->rel_name, stmt->from_clause);

    qry->unique_flag = NULL;

    /* 确定目标链表 */
    targetlist = make_target_list(pstate, stmt->cols, stmt->exprs);
    qry->target_list = transform_target_list(pstate, targetlist,
                                        TRUE /* INSERT */,
                                        FALSE/*非UPDATE*/);

    /* 确定WHERE子句 */
    qry->qual = transform_where_clause(pstate, stmt->where_clause);

    /* 现在,'范围表'不再改变 */
    qry->rtable = pstate->p_rtable;
    qry->result_relation = range_table_posn(pstate->p_rtable, stmt->rel_name);

    return (query_t *)qry;
}

/**
 * transform_select_stmt() -|- line 397
 *  转化一个SELECT语句.
 * @param: pstate[in]
 *         stmt[in]
 * @return: qry
 * @note:
 */
query_t *transform_select_stmt(parse_state_t *pstate, select_stmt_t *stmt)
{
    query_t *qry = make_node(query_t);

    qry->command_type = CMD_SELECT;

    /* 确定range table,将这些table的信息记录到pstate中
     * 此处的第二个参数为NULL,具体见makeRangeTable函数
     */
    make_range_table(pstate, NULL, stmt->from_clause);

    qry->rtable = pstate->p_rtable;

    qry->unique_flag = stmt->unique;		/* DINSTINCT utils */

    qry->into = stmt->into;				/* SELECT INTO utils */

    qry->is_portal = FALSE;

    /* fix the target list */
    qry->target_list = transform_target_list(pstate,
        stmt->target_list,
        FALSE, 	    /* is INSERT */
        FALSE); 	/* not UPDATE */

    /* fix WHERE clause */
    qry->qual = transform_where_clause(pstate, stmt->where_clause);

    /* fix ORDER clause */
    qry->sort_clause = transform_sort_clause(stmt->order_clause, qry->target_list, qry->unique_flag);

    /* fix GROUP BY clause */
    qry->group_clause = transform_group_clause(pstate, stmt->group_clause);

    return (query_t *)qry;
}

/**
 * transform_update_stmt() - line 442
 * 转化一个UPDATE语句.
 */
query_t *transform_update_stmt(parse_state_t *pstate, update_stmt_t *stmt)
{
    query_t *qry = make_node(query_t);

    qry->command_type = CMD_UPDATE;

    make_range_table(pstate, stmt->rel_name, stmt->from_clause);

    /* 确定目标列 */
    qry->target_list = transform_target_list(pstate,
                      stmt->target_list,
                      FALSE, /* 非INSERT */
                      TRUE   /* UPDATE */);

    /* 确定WHERE子句 */
    qry->qual = transform_where_clause(pstate,stmt->where_clause);

    qry->rtable = pstate->p_rtable;
    qry->result_relation = range_table_posn(pstate->p_rtable, stmt->rel_name);

    return (query_t *)qry;
}

/*****************************************************************************
 *
 * Transform Exprs, Aggs, etc.
 *
 *****************************************************************************/

/**
 * transform_expr - line 534
 *
 * @brief: analyze and transform expressions. Type checking and type casting is
 *    done here. The optimizer and the executor cannot handle the original
 *    (raw) expressions collected by the parse tree. Hence the transformation
 *    here.
 *
 * @param: pstate[in] - 用来辅助T_Ident类型中表达式的解析
 *         expr[in] - 被转换节点
 *
 * @return: result
 *
 * @note: 在本函数中,现在的设想是对应的*expr转化成一个树结构,
 *       之所以选择在此转化,是因为表达式的分析都在该函数中实现. - coanor, 2010.4.20
 */
static node_t* transform_expr(parse_state_t *pstate, node_t *expr)
{
    node_t *result = NULL;

    if (expr == NULL) {
        return NULL;
    }

    switch(node_tag(expr))
    {
        /**
         * 修改了词法文件后,除了表达式和常量之外的结果列都被当成是Ident类型,
         * 如NODE, POINT, ID,其实ID属于attr类型,但这里统一将其定为Ident
         * 类型,即将T_Attr和T_Ident统一处理.
         *
         * 对于T_a_const_t,目前没有考虑.
         *
         * 对于T_Ident类型的表达式,一般都是作为结果列或者WHERE表达式中的元素,
         * 对于这些表达式,其字段都是取自pstate中的range table或全局table_map
         * 中的那些字段,如果这些字段在这2个地方都找不到,那么就认为该SQL语句的
         * 执行结果是没有意义的,至少这些'找不到'的元素(字段),不会在最终结果中
         * 体现出来.
         */
    case T_ident_t:
        {
            ident_t *ident = (ident_t *)expr;
            bool isrel;
            RLTexpression_t *field;

            /* 对标识符(ident)而言，其肯定会在字段映射表中存在 - 10.4.23.coanor */
            const char *reln = parse_column_name(pstate, ident->name, &isrel);

            /**
             * 可能是一个列名(如ID)或者一个表名(UNIT1)
             *
             * 此处的reln不应该为NULL,因为ParseColumnName返回的总会是
         * 一个非空的字符串,除非ident->name本来就是一个空字符串或者
         * reln作为一个表名,在pstate中已经存在(实际上,这种情况也少见)
         */
        if (reln != NULL)
        {
            /**
             * 其实对于T_Ident类型而言，其转换成表达式树的过程比较简单，但却是
             * 转换大部分表达式的基石.其它类型的表达式，例如WHERE表达式中的字段等
             * 都是一步步递归到T_Ident类型的表达式转换才逐步构造起来的。
             *
             * 对于T_Ident类型的表达式(虽然从其表现形式上而言，更像一个变量),只需要指定
             * 其类型以及取值就行了，其类型一般只有一种，即field类型，其值的话，一般也就
             * 一个特定的字段名(如ID)，这个字段名在map_table中是可以索引的，该字段的取值类型
             * 也可以适量添加(如ID字段的类型为unsigned int型).但这些信息需要完善.2010.4.20 - coanor
             */

            /* 将ident构造成一个RLTexpression_t  -
             * 不管ident是一个table标识符还是一个字段标识符，
             * 此处统统将其转换成一个表达式,具体的判断在映射层处理. 10.4.23.coanor
             */
            field = rlt_exp_create(RLT_field_op);
            rlt_exp_single(field, (RLTexpression_t *)ident->name);

            result = (node_t *)field;
        }
        else
        {
            /*
             * 此else分支目前不做处理
             */
            printf("> error: column name \"%s\" does not exist.\n",  ident->name);

            /*
             * 此处查找不到的话，还是将其转换成表达式比较好，暂不实现，占楼...
             */
        }
        break;
    }
    case T_expr_t:
    {
        a_expr_t *a = (a_expr_t *)expr;
        RLTexpression_t	*exprTree;

        /* 一下主要是WHERE子句中的条件判断,很悬啊,可能还要增加一些代码 */
        switch(a->oper)
        {
        case OP:
            {
                node_t *lexpr = transform_expr(pstate, a->lexpr);
                node_t *rexpr = transform_expr(pstate, a->rexpr);
                /**
                 * 这里的make_op可以理解为构造表达式树的一个原型,
                 * 我们可以改写这个函数,将这3个参数转化成一颗表达式树.
                 */
                result = (node_t *)make_op(a->opname, lexpr, rexpr);
            }
            break;
        case ISNULL:
            {
            }
            break;
        case NOTNULL:
            {
            }
            break;
        case AND:
            {
                expr_t *expr = make_node(expr_t);
                node_t *lexpr = transform_expr(pstate, a->lexpr);
                node_t *rexpr = transform_expr(pstate, a->rexpr);

                if (expr_type(lexpr) != BOOLOID)
                    elog(WARN,
                         "left-hand size of AND is not bool");
                if (expr_type(rexpr) != BOOLOID)
                    elog(WARN,
                         "right-hand side of AND is not bool");

                expr->type_oid = BOOLOID;
                expr->op_type = AND_EXPR;
                expr->args = make_list(lexpr, rexpr, -1);
                result = (node_t *)expr;
            }
            break;
        case OR:
            {
                expr_t *expr = make_node(expr_t);
                node_t *lexpr = transform_expr(pstate, a->lexpr);
                node_t *rexpr = transform_expr(pstate, a->rexpr);

                if (expr_type(lexpr) != BOOLOID)
                    elog(WARN,
                         "left-hand side of OR is not bool");
                if (expr_type(rexpr) != BOOLOID)
                    elog(WARN,
                         "right-hand side of OR is not bool");

                expr->type_oid = BOOLOID;
                expr->op_type = OR_EXPR;
                expr->args = make_list(lexpr, rexpr, -1);
                result = (node_t *)expr;
            }
            break;
        case NOT:
            {
                expr_t *expr = make_node(expr_t);
                node_t *rexpr = transform_expr(pstate, a->rexpr);

                if (expr_type(rexpr) != BOOLOID)
                    elog(WARN,
                         "argument to NOT is not bool");

                expr->type_oid = BOOLOID;
                expr->op_type = NOT_EXPR;
                expr->args = make_list(rexpr, -1);
                result = (node_t *)expr;
            }
            break;
        }
        break;
    }

    case T_attr_t: {
        break;
    }

    case T_a_const_t: {
#if 0
        a_const_t *con = (a_const_t *)expr;

        parse_value_t *val = &(con->val);

        if (con->type_name != NULL)
            result = parser_typecast(val, con->type_name, -1);
        else
            result = (node_t *)make_const(val);
#endif
        break;

    }
    } /* switch(node_tag(expr)) */

    return result;
}

/**
 * parse_from_clause - line 760
 *  分解frmList,将其中的table信息存入pstate中
 * @param: pstate[in]
 *         frmList[in]
 * @return: void
 * @note:
 */
void parse_from_clause(parse_state_t *pstate, list_t *frmList)
{
    list_t *fl = frmList;

    while(fl != NIL)
    {
        range_var_t *r = (range_var_t *)lfirst(fl);
        rel_expr_t *baserel = r->rel_expr;
        range_tbl_entry_t *ent;
        char *relname = baserel->rel_name;
        char *refname = r->name;

        if (refname == NULL)
        {
            refname = relname;
        }

        /* 检查refname是否已经在pstate中存在 */
        if (range_table_posn(pstate->p_rtable, refname) != 0)
        {
            elog(WARN, "parser: range variable \"%s\" duplicated", refname);
        }

        ent = make_range_table_entry(relname, baserel->inh, refname);

        /* 指明该entry来自FROM子句. 在SQL中,target list
         * 只能来自'由FROM子句指定的范围表'中的列.
         *
         * Note:
         * 在目前的一些数据库实现中,如果指定的列在'FROM子句指定表'的列中没有,
         * 那么则创建一个临时的table,使得其包含指定列. coanor-2010.3.8 11:13
         */
        ent->in_from_cl = true;

        pstate->p_rtable = lappend(pstate->p_rtable, ent);
        fl = lnext(fl);
    }
}

/**
 * make_range_table - line 808
 *  根据指定的relation(optional)和FROM子句创建一个'表范围'(range table)
 * @param: pstate
 *         relname
 *         frmList 检查该List,将其中的表信息提取出来
 * @return: void
 * @note:
 */
void make_range_table(parse_state_t *pstate, const char *relname, list_t *frm_list)
{
    parse_from_clause(pstate, frm_list);

    /* 在transformSelectStmt中调用makeRangeTable,
     * relname参数为空 */
    if (relname == NULL)
    {
        return;
    }

    /* while transform_select_stmt(), call make_range_table()
     * soon return from here, I think transform_select_stmt()
     * don't care about the following code,because following
     * work has been done once in parse_from_clause(), but other stmt,
     * such as DELETE,INSERT, are interested with folloing work,
     * and they should do parse_from_clause(), and then check the
     * pstate->p_rtable for replication. - coanor - 10.3.31
     */

    /* parse_from_clause has lappend some rtable to pstate,
     * here, we search for someone - coanor,10.3.23.
     */
    if (range_table_posn(pstate->p_rtable, relname) < 1)
    {
        range_tbl_entry_t *ent;
        ent = make_range_table_entry(relname, FALSE, relname);
        pstate->p_rtable = lappend(pstate->p_rtable, ent);
    }
#if 0
    x = range_table_posn(pstate->p_rtable, relname);
    pstate->parser_current_rel = heap_openr(var_no_get_rel_name(pstate, x));

    if (pstate->parser_current_rel == NULL)
    {
        elog(WARN, "invalid relation name");
    }
#endif
}

/**
 * exptType() - line 834
 *  返回表达式的Oid(用于类型检查)
 *
 * @param: expr 表达式节点
 * @return: type 表达式节点类型编号
 * @note:
 */
oid_t expr_type(node_t *expr)
{
    oid_t type = UNKNOWNOID;
    switch(node_tag(expr))
    {
    case T_func_t:
        break;
    case T_iter_t:
        break;
    case T_var_t:
        break;
    case T_expr_t:
        type = ((expr_t *)expr)->type_oid;
        break;
    case T_const_t:
        break;
    case T_aggreg_t:
        break;
    case T_param_t:
        break;
    case T_ident_t:
        break;
    default:
        elog(WARN,
            "expr_type: don't know how to get type for %d node",
            node_tag(expr));
        break;
    }
    return type;
}

/**
 * transform_where_clause()
 * \brief: 转化WHERE中的过滤条件并确定条件的类型为Boolean.
 */
node_t *transform_where_clause(parse_state_t *pstate, node_t *a_expr)
{
    node_t *qual;

    if (a_expr == NULL)
        return (node_t *)NULL;	/* 无过滤条件 */

    qual = transform_expr(pstate, a_expr);

    if (expr_type(qual) != BOOLOID)
        elog(WARN, "WHERE clause must return type bool");

    return qual;
}

/**
 *
 */
int range_table_posn(list_t *rtable, const char *range_var)
{
    int index;
    list_t *temp;

    index  = 1;
    temp = rtable;

    while (temp != NIL)
    {
        range_tbl_entry_t *rt_entry = (range_tbl_entry_t *)lfirst(temp);

        if (!strcmp(rt_entry->ref_name, range_var))
        {
            return index;
        }

        temp = lnext(temp);
        index++;
    }
    return 0;
}

/**
 *
 */
list_t *make_target_list(parse_state_t *pstate, list_t *cols, list_t *exprs)
{
    return (list_t *)NULL;
}

/**
 * transform_target_list() - line 1064
 * @desc: 将Restarget链表转换成TargetEntry链表
 *
 * @param: pstate[in]
 *         targetlist[in]
 *         isInsert[in]
 *         isUpdate[in]
 *
 * @return: p_target
 *
 * @note:
 */
list_t *transform_target_list(parse_state_t *pstate,
                                 list_t *targetlist,
                                 bool isInsert,
                                 bool isUpdate)/* 如果是UPDATE或INSERT语句,那么此时的table
                                                * 是作为结果列来操作 */
{
    list_t *p_target = NIL;
    list_t *temp = NIL;

    /*
     * 遍历targetlist,对于每个target,都要一一解析出来
     */
    while (targetlist != NIL)
    {

        res_target_t *res = (res_target_t *)lfirst(targetlist);
        node_t *expr;

        /* 根据不同的target类型,分别处理 */
        switch(node_tag(res->val))
        {
            /* 最主要的还是标识符... */
            case T_ident_t: {
                oid_t type_id;
                int type_len;
                char *ident_name;
                char *resname;

                ident_name = ((ident_t *)res->val)->name;

                /**
                 * 在target中可能含有表达式,故解析之
                 * 此处已经将节点转换成表达式树结构，但仍以Node*返回,
                 * 在得到整个Query之后再将其中的表达式提取出来.
                 */
                expr = transform_expr(pstate, (node_t *)res->val);

                /*
                 * 如果表达式生成出错,即相应的结果列出错,
                 * 那么不进行进一步的处理.
                 */
                if (expr == NULL)
                {
                    targetlist = lnext(targetlist);
                    continue;
                }
                break;
                }
            case T_ParamNo:
            case T_FuncCall:
            case T_a_const_t:
            case T_expr_t:
                /* 在结果列中暂不支持表达式处理 */
                break;
            case T_attr_t:
                /* T_Attr类型在T_Ident中处理 */
                break;
            default:
                elog(WARN,
                    "internal error: do not know how to transform targetlist");
                break;
        } /* end switch node_tag(res->val) */

        /* 此处对于新加入的tent,应该检查其是否跟前面加入的有重复,目前先不检查.
         * 也可以在最后添加一个处理,去掉其中的重复元素.
         */
        if (NIL == p_target)
        {
            p_target = temp = lcons(expr, NIL);
        }
        else
        {
            lnext(temp) = lcons(expr, NIL);
            temp = lnext(temp);
        }

        /* 接着处理targetlist中的下一个元素 */
        targetlist = lnext(targetlist);
    }
    return p_target;
}

/**
 * parse_column_name - line 2237
 *  查找pstate中的表,考察name是否在这些表中作为列存在,
 *  并设置isRelName,返回relname,若不是列,则返回NIL.
 *
 * @param: pstate[in]
 *         name[in]
 *         is_rel_name[in&out]
 * @return: refname | NULL
 */
const char *parse_column_name(parse_state_t *pstate, char *name, bool *is_rel_name)
{
    list_t *et;
    relation_t rd;
    list_t *rtable;

    /* 遍历pstate->p_table,检查name是否是一个已经存在的表名 */
    if (range_table_posn(pstate->p_rtable, name) != 0)
    {
        *is_rel_name = TRUE;
        return NULL;
    }

    /* 屏蔽上面的代码后,默认表的查找范围就是pstate->p_rtable */
    rtable = pstate->p_rtable;

    /* 查找FROM链表中的所有relation,一旦在表中找到这些属性,则返回.
     * 此处的relation是在解析FROM中得到的range table.
     */
    for_each(et, rtable)
    {
        range_tbl_entry_t *rte = (range_tbl_entry_t *)lfirst(et);
        const char *relname = rte->rel_name;
        const char *refname = rte->ref_name;
        oid_t rel_dim = 1;    /* 表维度 */
        const char *p = refname;

        /* 通过表名,获取其对应于openPlant中的ID
         * 可能是点ID,或者是节点ID,可以是数据库ID吗?
         */

        /* 对于一个特定的relname,可以通过其点名格式来判断
         * 其表的类型：
         *  表名中没有'.',则默认为db
         *  有1个'.', 默认为node
         *  有2个'.', 默认为point
         *  有3个'.', 默认为attr
         *
         * 在目前的实现中,只允许一个维度的表操作,所以在
         * rtable中所有的表结构都应该是一样的.即rel_dim相同.
         */
        while (*p++ != '\0')
        {
            if (*p == '.')
                ++rel_dim;
        }

        /**
         * 此处查找一个属性是否属于一个表 -
         * 对于每个表,都有相应的属性配置,即通过xml文件来配置这些属性,
         * 而get_attnum的实现就是,首先要判断表的类型(W3|UNIT|POINT?),
         * 根据表类型而查找相应的表字段.就目前而言,对同一类型的表,其
         * 属性字段是一样的,通过xml文件在程序外配置.
         *
         * 此处的get_attnum应该修改,第一个参数应该是表类型(W3|UNIT|POINT),
         * 因为无论任何属性,其只能是这三种表的属性之一,顾第一个参数只需要
         * 告知表类型即可.函数通过查找g_table_map来确定属性的id是否是这种
         * 类型表的属性字段.
         */
        if (get_attnum(rel_dim, name) != INVALID_ATTR_ID)
        {
            /* 既然列名在表中找到,则它不可能是一个表
             * 此种情况只出现在POINT.attr字段上,实际上
             * W3.UNIT或UNIT.POINT都不可能是属性,它们实
             * 际上还是一个二维表.
             *
             * 已对POINT中的某个attr编号.
             * 目前POINT中的字段基本稳定,不会有什么增减.
             */
            if (rel_dim == 4)
            {
                *is_rel_name = FALSE;
            }
            else
            {
                *is_rel_name = TRUE;
            }
            return refname;
        }
    }

    return NULL;
}

/**
 * make_op - line 296
 *
 * @desc: Operator expression construction.
 * Transform operator expression ensuring type compatibility.
 * This is where some type conversion happens.
 *
 * @param: opname[in]
 *         ltree[in]
 *         rtree[in]
 *
 * @ret: result
 *
 * @XXX:
 */
expr_t *make_op(char *opname, node_t *ltree, node_t *rtree)
{
    int ltype_id, rtype_id;

    expr_t *result;

    /* ... */
    return result;
}

/**
 * make_range_table_entry()
 *  根据rel_name创建一个range_tbl_entry_t
 * @param: rel_name[in]
 *         inh[in] 未用
 *         ref_name 未用
 * @return: range_tbl_entry
 * @note: 此函数构造的range_tbl_entry_t对象怎么释放?
 */
range_tbl_entry_t *make_range_table_entry(const char *rel_name, bool inh, const char *ref_name)
{
    relation_t relation;
    range_tbl_entry_t *ent = make_node(range_tbl_entry_t);

    ent->rel_name = pstrdup(rel_name);
    ent->ref_name = ref_name;

    ent->rel_name = rel_name;

    return ent;
}

/**
 * get_attnum()
 *  \brief: given the relation id and the attribute name,
 *          return the "attnum" field from the attribute relation
 *
 *	        通过查找xml文件,确定给定的属性名是否在表id为relid的表中存在,
 *	        返回其属性id.
 * \param: rel_dim[in]
 *         att_name[in]
 * \return: int
 *
 * \note: 预计的实现是,在程序外部配置每种类型表的字段表(W3\UNIT\POINT),
 *	       程序启动后就初始化表中各个属性,以全局变量的形式共享,每次查找即
 *         查询该表.
 */
unsigned int get_attnum(int rel_dim, char *att_name)
{
    table_map_t *t_map;

    if (*att_name == '*')
    {
        return STAR_ATTR_ID;
    }

    t_map = scan_table_map(att_name, rel_dim);
    if (t_map != NULL)
    {
        return t_map->field_id;
    }
    else
    {
        return INVALID_ATTR_ID;
    }
}

list_t *transform_sort_clause(list_t *order_list, list_t *target_list, char *unique_flag)
{
        list_t *sortlist = NIL;
        list_t *s;
        list_t *i;

        return sortlist;
}

list_t *transform_group_clause(parse_state_t *pstate, list_t *grouplist)
{
        list_t *glist = NIL;
        list_t *gl;
#if 0
        while (grouplist != NIL) {
                group_clause_t *grpcl = make_node(group_clause_t);
                var_t *group_attr = (var_t *)transform_expr(pstate, (node_t *)lfirst(grouplist));

                if (node_tag(group_attr) != T_var_t)
                        elog(WARN, "parser:can only specify attribute in GROUP BY");

                grpcl->grp_attr = group_attr;
                grpcl->grp_op_oid = any_ordering_op(group_attr->var_type);

                if (glist == NIL)
                        gl = glist = lcons(grpcl, NIL);
                else {
                        lnext(gl) = lcons(grpcl, NIL);
                        gl = lnext(gl);
                }
                grouplist = lnext(grouplist);
        }
#endif
        return glist;
}
